home *** CD-ROM | disk | FTP | other *** search
/ Aminet 7 / Aminet 7 - August 1995.iso / Aminet / comm / term / XPRZ35R_SRC.lha / Utils.c < prev    next >
C/C++ Source or Header  |  1995-01-03  |  48KB  |  1,502 lines

  1.  /**********************************************************************
  2.   * Utils.c: Miscellaneous support routines for xprzmodem.library;
  3.   * Version 2.10, 12 February 1991, by Rick Huebner.
  4.   * Released to the Public Domain; do as you like with this code.
  5.   *
  6.   * Version 2.50, 15 November 1991, by William M. Perkins.  Added code
  7.   * to update_rate() function in utils.c to avoid the Guru # 80000005
  8.   * you would have gotten if you had decided to adjust the system clock
  9.   * back during an upload or download.
  10.   *
  11.   * Mysprintf() function to replace sprintf() and proto code to use
  12.   * libinit.o and linent.o library code was supplied by Jim Cooper of SAS.
  13.   *
  14.   * Version 2.61, 3 July 1993 Mysprintf changed to xprsprintf(), written
  15.   * in Assembler, because under SAS/C the old code running not correctly.
  16.   *
  17.   * Version 2.62, 27 July 1993 build in variable Blocksize.
  18.   *
  19.   * Version 2.63, 30 July 1993 build in locale, by Rainer Hess
  20.   *
  21.   * Version 2.64,  3 Aug 1993 global vaiable Blocksize, now in
  22.   *                 struct Vars, by Rainer Hess
  23.   *
  24.   *                4 Aug 1993 changes in update_rate() function because
  25.   * it always GURU 8000 0005 on little files (testet with 2 byte-file)
  26.   * when you send. If on receiver the file exists when receiver ask for
  27.   * overwrite, the machine crash if you click overwrite on receiver.
  28.   * Testet on Term 3.4 -> Ncomm 2.0, by Rainer Hess
  29.   *
  30.   * Version 3.2   11 Nov 1994 modifications to implement FTN operations
  31.   *               by Roert Williamson
  32.   * Version 3.2   19 Nov 1994 version string added, XPR 2.001 support added
  33.   * Version 3.5   Jan 1,1994 added rxtimeout, xpr2ext setup options   
  34.   **********************************************************************/
  35.  
  36. #include "xprzmodem_all.h"
  37.  
  38. #define CATCOMP_NUMBERS
  39. #include "xprzmodem_catalog.h"
  40.  
  41.  
  42. /*
  43.  * Transfer options to use if XProtocolSetup not called
  44.  */
  45. #ifdef zedzap
  46. struct SetupVars Default_Config =
  47. {
  48.   NULL,       /* = *matchptr  */
  49.   NULL,       /* = *bufpos    */
  50.   0,          /* = buflen     */
  51.   "N",        /* option_t[2]  Set Text translation mode */
  52.   "R",        /* option_o[2]  Overwrite mode */
  53.   "16",       /* option_b[8]  Buffer size */
  54.   "0",        /* option_f[8]  Frame size */
  55.   "30",       /* option_e[8]  Error count */
  56.   "N",        /* option_s[4]  Send full directory path */
  57.   "N",        /* option_r[4]  Receive full directory path */
  58.   "N",        /* option_a[4]  Auto-activate mode */
  59.   "N",        /* option_d[4]  Delete after sending */
  60.   "Y",        /* option_k[4]  Keep partial files */
  61.   "",         /* option_p[256] Path to use for received files */
  62.   "8192",     /* option_m[8]  Set maximum packet size */
  63.   "0",        /* option_c[8]  Set Link BPS Rate */
  64.   "Y",        /* option_n[4]  Send if there are no files */
  65.   "N",        /* option_q[4]  Enable DirectZap escape only CAN */
  66.   "Y",        /* option_z[4]  Enable FTN mode */
  67.   "Y",        /* option_y[4]  Enable XPR 2.001 results */
  68.   "100"       /* option_x[8]  StartTimeout */
  69. };
  70. #else
  71. struct SetupVars Default_Config =
  72. {
  73.   NULL,       /* = *matchptr  */
  74.   NULL,       /* = *bufpos    */
  75.   0,          /* = buflen     */
  76.   "C",        /* option_t[2]  Set Text translation mode */
  77.   "N",        /* option_o[2]  Overwrite mode */
  78.   "16",       /* option_b[8]  Buffer size */
  79.   "0",        /* option_f[8]  Frame size */
  80.   "10",       /* option_e[8]  Error count */
  81.   "N",        /* option_s[4]  Send full directory path */
  82.   "N",        /* option_r[4]  Receive full directory path */
  83.   "Y",        /* option_a[4]  Auto-activate mode */
  84.   "N",        /* option_d[4]  Delete after sending */
  85.   "Y",        /* option_k[4]  Keep partial files */
  86.   "",         /* option_p[256] Path to use for received files */
  87.   "1024",     /* option_m[8]  Set maximum packet size */
  88.   "0",        /* option_c[8]  Set Link BPS Rate */
  89.   "N",        /* option_n[4]  Send if there are no files */
  90.   "N",        /* option_q[4]  Enable DirectZap escape only CAN */
  91.   "N",        /* option_z[4]  Enable FTN mode */
  92.   "N",        /* option_y[4]  Enable XPR 2.001 results */
  93.   "100"       /* option_x[8]  StartTimeout */
  94. };
  95. #endif
  96.  
  97. #ifdef DEBUGLOG
  98. UBYTE DebugName[] = "T:XDebug.Log";
  99. void *DebugLog = NULL;
  100. #endif
  101.  
  102. struct DosLibrary *DOSBase;
  103. struct ExecBase *SysBase;
  104.  
  105. #ifdef UP_TO_2X
  106. struct Library *UtilityBase;
  107. #endif
  108.  
  109. #define LIBRARY_ANY 0L
  110.  
  111. #define LocaleBase li.li_LocaleBase
  112. #define catalog    li.li_Catalog
  113.  
  114. struct LocaleInfo li;
  115.  
  116. struct TagItem LocalTags[3] =
  117. {
  118.   OC_BuiltInLanguage, (ULONG) "english",
  119.   OC_Version, 1,
  120.   TAG_DONE
  121. };
  122.  
  123. /**********************************************************
  124.  *      int __UserLibInit(struct Library *libbase)
  125.  **********************************************************/
  126. int __saveds __asm
  127. __UserLibInit (register __a6 struct MyLibrary *libbase)
  128. {
  129.   SysBase = *(struct ExecBase **) 4L;
  130.   if (!(DOSBase = (struct DosLibrary *) OpenLibrary ("dos.library", LIBRARY_ANY)))
  131.     return (RETURN_FAIL);
  132.  
  133. #ifdef UP_TO_2X
  134.   if (!(UtilityBase = OpenLibrary ("utility.library", 37L)))
  135.     return (RETURN_FAIL);
  136. #endif
  137.  
  138.   if (LocaleBase = OpenLibrary ("locale.library", 38L))
  139.     catalog = OpenCatalogA (NULL, "xprzmodem.catalog", &LocalTags[0]);
  140.  
  141.   return (RETURN_OK);
  142. }                                /* End of __UserLibInit() */
  143.  
  144. /**********************************************************
  145.  *      void __UserLibCleanup(struct Library *libbase)
  146.  **********************************************************/
  147. void __saveds __asm
  148. __UserLibCleanup (register __a6 struct MyLibrary *libbase)
  149. {
  150.   if (DOSBase)
  151.     CloseLibrary ((struct Library *) DOSBase);
  152.  
  153. #ifdef UP_TO_2X
  154.   if (UtilityBase)
  155.     CloseLibrary (UtilityBase);
  156. #endif
  157.  
  158.   if (LocaleBase)
  159.     {
  160.       if (catalog)
  161.         CloseCatalog (catalog);
  162.       CloseLibrary (LocaleBase);
  163.     }
  164. }                                /* End of __UserLibCleanup() */
  165.  
  166. /**********************************************************
  167.  *      long XProtocolSetup(struct XPR_IO *xio)
  168.  *
  169.  * Called by comm program to set transfer options
  170.  **********************************************************/
  171. long __saveds __asm
  172. XProtocolSetup (register __a0 struct XPR_IO *xio)
  173. {
  174.   struct SetupVars *sv, tempsv;
  175.   struct xpr_option *option_ptrs[19];
  176.   struct xpr_option *optr, xo_hdr, 
  177.     xo_t, xo_o, xo_b, xo_f, xo_e, xo_s,
  178.     xo_r, xo_a, xo_d, xo_k, xo_p, xo_m, 
  179.     xo_c, xo_n, xo_q, xo_z, xo_y, xo_x;
  180.   UBYTE buf[512], *p;
  181.   long i, len;
  182.  
  183.   /* Allocate memory for transfer options string */
  184.   if (!(sv = (void *) xio->xpr_data))
  185.   {
  186. /*      xio->xpr_data = AllocMem ((ULONG) sizeof (struct SetupVars), MEMF_CLEAR); */
  187.       xio->xpr_data = AllocMem ((long) sizeof (struct SetupVars), MEMF_CLEAR);
  188.       if (!(sv = (void *) xio->xpr_data))
  189.         {
  190.           ioerr (xio, "Not enough memory!");
  191.           return XPRS_FAILURE;
  192.         }
  193.       /* Start out with default options; merge user changes into defaults */
  194.       *sv = Default_Config;
  195.   }
  196.  
  197.   /* If options string passed by comm prog, use it; else prompt user */
  198.   if (xio->xpr_filename)
  199.     strcpy (buf, xio->xpr_filename);
  200.   else
  201.   {
  202.     /* If xpr_options() implemented by comm program, use it */
  203.     if (xio->xpr_extension >= 1 && xio->xpr_options)
  204.     {
  205.         /*
  206.            * Let user edit temp copy of options so we can ignore invalid
  207.            * entries.  Have to init all this crud the hard way 'cause it's
  208.            * got to be on the stack in order to maintain reentrancy
  209.          */
  210.         tempsv = *sv;
  211.         xo_hdr.xpro_description = GetLocalString( &li, MSG_ZMODEM_OPTIONS );
  212.         xo_hdr.xpro_type = XPRO_HEADER;
  213.         xo_hdr.xpro_value = NULL;
  214.         xo_hdr.xpro_length = 0;
  215.         option_ptrs[0] = &xo_hdr;
  216.  
  217.         xo_t.xpro_description = GetLocalString( &li, MSG_TEXT_MODE );
  218.         xo_t.xpro_type = XPRO_STRING;
  219.         xo_t.xpro_value = tempsv.option_t;
  220.         xo_t.xpro_length = sizeof (tempsv.option_t);
  221.         option_ptrs[1] = &xo_t;
  222.  
  223.         xo_o.xpro_description = GetLocalString( &li, MSG_OVERWRITE_MODE );
  224.         xo_o.xpro_type = XPRO_STRING;
  225.         xo_o.xpro_value = tempsv.option_o;
  226.         xo_o.xpro_length = sizeof (tempsv.option_o);
  227.         option_ptrs[2] = &xo_o;
  228.  
  229.         xo_b.xpro_description = GetLocalString( &li, MSG_IO_BUFFER_SIZE );
  230.         xo_b.xpro_type = XPRO_LONG;
  231.         xo_b.xpro_value = tempsv.option_b;
  232.         xo_b.xpro_length = sizeof (tempsv.option_b);
  233.         option_ptrs[3] = &xo_b;
  234.  
  235.         xo_f.xpro_description = GetLocalString( &li, MSG_FRAME_SIZE );
  236.         xo_f.xpro_type = XPRO_LONG;
  237.         xo_f.xpro_value = tempsv.option_f;
  238.         xo_f.xpro_length = sizeof (tempsv.option_f);
  239.         option_ptrs[4] = &xo_f;
  240.  
  241.         xo_e.xpro_description = GetLocalString( &li, MSG_ERROR_LIMIT );
  242.         xo_e.xpro_type = XPRO_LONG;
  243.         xo_e.xpro_value = tempsv.option_e;
  244.         xo_e.xpro_length = sizeof (tempsv.option_e);
  245.         option_ptrs[5] = &xo_e;
  246.  
  247.         xo_a.xpro_description = GetLocalString( &li, MSG_AUTO_ACTIVATE_RECEIVER );
  248.         xo_a.xpro_type = XPRO_BOOLEAN;
  249.         xo_a.xpro_value = tempsv.option_a;
  250.         xo_a.xpro_length = sizeof (tempsv.option_a);
  251.         option_ptrs[6] = &xo_a;
  252.  
  253.         xo_d.xpro_description = GetLocalString( &li, MSG_DELETE_AFTER_SENDING );
  254.         xo_d.xpro_type = XPRO_BOOLEAN;
  255.         xo_d.xpro_value = tempsv.option_d;
  256.         xo_d.xpro_length = sizeof (tempsv.option_d);
  257.         option_ptrs[7] = &xo_d;
  258.  
  259.         xo_k.xpro_description = GetLocalString( &li, MSG_KEEP_PARTIAL_FILES );
  260.         xo_k.xpro_type = XPRO_BOOLEAN;
  261.         xo_k.xpro_value = tempsv.option_k;
  262.         xo_k.xpro_length = sizeof (tempsv.option_k);
  263.         option_ptrs[8] = &xo_k;
  264.  
  265.         xo_s.xpro_description = GetLocalString( &li, MSG_SEND_FULL_PATH );
  266.         xo_s.xpro_type = XPRO_BOOLEAN;
  267.         xo_s.xpro_value = tempsv.option_s;
  268.         xo_s.xpro_length = sizeof (tempsv.option_s);
  269.         option_ptrs[9] = &xo_s;
  270.  
  271.         xo_r.xpro_description = GetLocalString( &li, MSG_USE_RECEIVED_PATH );
  272.         xo_r.xpro_type = XPRO_BOOLEAN;
  273.         xo_r.xpro_value = tempsv.option_r;
  274.         xo_r.xpro_length = sizeof (tempsv.option_r);
  275.         option_ptrs[10] = &xo_r;
  276.  
  277.         xo_p.xpro_description = GetLocalString( &li, MSG_DEFAULT_RECEIVE_PATH );
  278.         xo_p.xpro_type = XPRO_STRING;
  279.         xo_p.xpro_value = tempsv.option_p;
  280.         xo_p.xpro_length = sizeof (tempsv.option_p);
  281.         option_ptrs[11] = &xo_p;
  282.  
  283.         xo_m.xpro_description = GetLocalString( &li, MSG_MAXIMUM_BLOCK_SIZE );
  284.         xo_m.xpro_type = XPRO_LONG;
  285.         xo_m.xpro_value = tempsv.option_m;
  286.         xo_m.xpro_length = sizeof (tempsv.option_m);
  287.         option_ptrs[12] = &xo_m;
  288.  
  289.         xo_m.xpro_description = GetLocalString( &li, MSG_LINK_RATE );
  290.         xo_m.xpro_type = XPRO_LONG;
  291.         xo_m.xpro_value = tempsv.option_c;
  292.         xo_m.xpro_length = sizeof (tempsv.option_c);
  293.         option_ptrs[13] = &xo_c;
  294.  
  295.         xo_m.xpro_description = GetLocalString( &li, MSG_SEND_NO_FILES );
  296.         xo_m.xpro_type = XPRO_BOOLEAN;
  297.         xo_m.xpro_value = tempsv.option_n;
  298.         xo_m.xpro_length = sizeof (tempsv.option_n);
  299.         option_ptrs[14] = &xo_n;
  300.  
  301.         xo_m.xpro_description = GetLocalString( &li, MSG_ESCAPE_ONLY_ZCAN );
  302.         xo_m.xpro_type = XPRO_BOOLEAN;
  303.         xo_m.xpro_value = tempsv.option_q;
  304.         xo_m.xpro_length = sizeof (tempsv.option_q);
  305.         option_ptrs[15] = &xo_q;
  306.  
  307.         xo_m.xpro_description = GetLocalString( &li, MSG_FTN_ZMODEM );
  308.         xo_m.xpro_type = XPRO_BOOLEAN;
  309.         xo_m.xpro_value = tempsv.option_z;
  310.         xo_m.xpro_length = sizeof (tempsv.option_z);
  311.         option_ptrs[16] = &xo_z;
  312.  
  313.         xo_m.xpro_description = GetLocalString( &li, MSG_XPR_EXT );
  314.         xo_m.xpro_type = XPRO_BOOLEAN;
  315.         xo_m.xpro_value = tempsv.option_y;
  316.         xo_m.xpro_length = sizeof (tempsv.option_y);
  317.         option_ptrs[17] = &xo_y;
  318.  
  319.         xo_m.xpro_description = GetLocalString( &li, MSG_STARTUP_TIMEOUT );
  320.         xo_m.xpro_type = XPRO_LONG;
  321.         xo_m.xpro_value = tempsv.option_x;
  322.         xo_m.xpro_length = sizeof (tempsv.option_x);
  323.         option_ptrs[18] = &xo_x;
  324.  
  325.  
  326.         /* Convert Y/N used elsewhere into "yes"/"no" required by spec */
  327.         for (i = 6; i <= 10; ++i)
  328.         {
  329.           optr = option_ptrs[i];
  330.           strcpy (optr->xpro_value, (*optr->xpro_value == 'Y') ? "yes" : "no");
  331.         }
  332.         for (i = 14; i <= 17; ++i)
  333.         {
  334.           optr = option_ptrs[i];
  335.           strcpy (optr->xpro_value, (*optr->xpro_value == 'Y') ? "yes" : "no");
  336.         }
  337.  
  338.         (*xio->xpr_options) (19L, option_ptrs);
  339.  
  340.         /* Convert "yes"/"no" or "on"/"off" into Y/N */
  341.         for (i = 6; i <= 10; ++i)
  342.         {
  343.           optr = option_ptrs[i];
  344.           strcpy (optr->xpro_value, (!stricmp (optr->xpro_value, "yes")
  345.                      || !stricmp (optr->xpro_value, "on")) ? "Y" : "N");
  346.         }
  347.         for (i = 14; i <= 17; ++i)
  348.         {
  349.           optr = option_ptrs[i];
  350.           strcpy (optr->xpro_value, (!stricmp (optr->xpro_value, "yes")
  351.                      || !stricmp (optr->xpro_value, "on")) ? "Y" : "N");
  352.         }
  353.         /* Convert xpr_options() results into parseable options string */
  354.         xprsprintf (buf, "T%s,O%s,B%s,F%s,E%s,A%s,D%s,K%s,S%s,R%s,P%s,M%s,C%s,N%s,Q%s,Z%s",
  355.           tempsv.option_t, tempsv.option_o, tempsv.option_b, tempsv.option_f,
  356.           tempsv.option_e, tempsv.option_a, tempsv.option_d, tempsv.option_k,
  357.           tempsv.option_s, tempsv.option_r, tempsv.option_p, tempsv.option_m,
  358.           tempsv.option_c, tempsv.option_n, tempsv.option_q, tempsv.option_z,
  359.           tempsv.option_y, tempsv.option_x);
  360.         /* If xpr_options() not provided, try xpr_gets() instead */
  361.     }
  362.     else
  363.     {
  364.       /* Start buffer with current settings so user can see/edit them. */
  365.       xprsprintf (buf, "T%s,O%s,B%s,F%s,E%s,A%s,D%s,K%s,S%s,R%s,P%s,M%s,C%s,N%s,Q%s,Z%s",
  366.           sv->option_t, sv->option_o, sv->option_b, sv->option_f,
  367.           sv->option_e, sv->option_a, sv->option_d, sv->option_k,
  368.           sv->option_s, sv->option_r, sv->option_p, sv->option_m,
  369.           sv->option_c, sv->option_n, sv->option_q, sv->option_z,
  370.           sv->option_y, sv->option_x);
  371.       if (xio->xpr_gets)
  372.         (*xio->xpr_gets) ( GetLocalString( &li, MSG_ZMODEM_OPTIONS ), buf);
  373.     }
  374.   }
  375.   /* Upshift options string for easier parsing */
  376.   strupr (buf);
  377.  
  378.   /*
  379.      * Merge new T(ext) option into current settings if given
  380.      *  "TY" = Force Text mode on,
  381.      *  "TN" = Force Text mode off,
  382.      *  "T?" = Use other end's text mode suggestion (default to binary)
  383.      *  "TC" = Ask Comm program for file type
  384.    */
  385.   if (p = find_option (buf, 'T'))
  386.   {
  387.     if (*p == 'Y' || *p == 'N' || *p == '?' || *p == 'C') *sv->option_t = *p;
  388.       else ioerr (xio,  GetLocalString( &li, MSG_INVALID_T_FLAG ));
  389.   }
  390.  
  391.   /*
  392.      * Merge new O(verwrite) option into current settings if given
  393.      *  "OY" = Yes, delete old file and replace with new one,
  394.      *  "ON" = No, prevent overwrite by appending ".dup" to avoid name collision,
  395.      *  "OR" = Resume transfer at end of existing file,
  396.      *  "OS" = Skip file if it already exists; go on to next
  397.    */
  398.   if (p = find_option (buf, 'O'))
  399.   {
  400.     if (*p == 'R' && !xio->xpr_finfo)
  401.       ioerr (xio, GetLocalString( &li, MSG_NO_XPR_FINFO ));
  402.     else if (*p == 'Y' || *p == 'N' || *p == 'R' || *p == 'S')
  403.       *sv->option_o = *p;
  404.     else ioerr (xio, GetLocalString( &li, MSG_INVALID_O_FLAG ));
  405.   }
  406.  
  407.   /*
  408.      * Merge new B(uffer) setting into current settings if given
  409.      * Size of file I/O buffer in kilobytes
  410.    */
  411.   if (p = find_option (buf, 'B'))
  412.   {
  413.     len = atol (p);
  414.     if (len < 1) len = 1;
  415.     xprsprintf (sv->option_b, "%ld", len);
  416.   }
  417.  
  418.   /*
  419.      * Merge new F(ramelength) setting into other settings if given
  420.      * Number of bytes we're willing to send or receive between ACKs.
  421.      * 0 = unlimited; nonstop streaming data
  422.    */
  423.   if (p = find_option (buf, 'F'))
  424.   {
  425.     len = atol (p);
  426.     if (len < 0) len = 0;
  427.     if (len > 0 && len < MINBLOCK) len = MINBLOCK;
  428.     xprsprintf (sv->option_f, "%ld", len);
  429.   }
  430.  
  431.   /*
  432.      * Merge new E(rror limit) setting into other settings if given
  433.      * Number of sequential errors which will cause an abort
  434.    */
  435.   if (p = find_option (buf, 'E'))
  436.   {
  437.     len = atol (p);
  438.     if (len < 1) len = 1;
  439.     if (len > 32767) len = 32767;
  440.     xprsprintf (sv->option_e, "%ld", len);
  441.   }
  442.  
  443.   /*
  444.      * Merge new A(uto-activate) setting into other settings if given
  445.      *  "AY" = Automatically call XProtocolReceive() if ZRQINIT string received
  446.      *  "AN" = Don't look for ZRQINIT; user will explicitly activate receive
  447.    */
  448.   if (p = find_option (buf, 'A'))
  449.   {
  450.     if (*p == 'Y' || *p == 'N') *sv->option_a = *p;
  451.       else ioerr (xio, GetLocalString( &li, MSG_INVALID_A_FLAG ));
  452.   }
  453.  
  454.   /*
  455.      * Merge new D(elete after sending) setting into other options
  456.      *  "DY" = Delete files after successfully sending them
  457.      *  "DN" = Don't delete files after sending
  458.    */
  459.   if (p = find_option (buf, 'D'))
  460.   {
  461.     if (*p == 'Y' && (xio->xpr_extension < 2 || !xio->xpr_unlink))
  462.       ioerr (xio, GetLocalString( &li, MSG_NO_DY_XPR_UNLINK ));
  463.     else if (*p == 'Y' || *p == 'N') *sv->option_d = *p;
  464.     else ioerr (xio, GetLocalString( &li, MSG_INVALID_D_FLAG ));
  465.   }
  466.  
  467.   /*
  468.      * Merge new K(eep partial files) setting into other options
  469.      *  "KY" = Keep partially-received file fragments to allow later resumption
  470.      *  "KN" = Delete partially-received file fragments
  471.    */
  472.   if (p = find_option (buf, 'K'))
  473.   {
  474.     if (*p == 'N' && (xio->xpr_extension < 2 || !xio->xpr_unlink))
  475.       ioerr (xio, GetLocalString( &li, MSG_NO_KN_XPR_UNLINK ));
  476.     else if (*p == 'Y' || *p == 'N') *sv->option_k = *p;
  477.     else ioerr (xio, GetLocalString( &li, MSG_INVALID_K_FLAG ));
  478.   }
  479.  
  480.   /*
  481.      * Merge new S(end full path) setting into other options
  482.      *  "SY" = Send full filename including directory path to receiver
  483.      *  "SN" = Send only simple filename portion, not including directory path
  484.    */
  485.   if (p = find_option (buf, 'S'))
  486.   {
  487.     if (*p == 'Y' || *p == 'N') *sv->option_s = *p;
  488.       else ioerr (xio, GetLocalString( &li, MSG_INVALID_S_FLAG ));
  489.   }
  490.  
  491.   /*
  492.      * Merge new R(eceive path) setting into other options
  493.      *  "RY" = Use full filename exactly as received; don't use P option path
  494.      *  "RN" = Ignore received directory path if any; use path from P option
  495.    */
  496.   if (p = find_option (buf, 'R'))
  497.   {
  498.     if (*p == 'Y' || *p == 'N') *sv->option_r = *p;
  499.       else ioerr (xio, GetLocalString( &li, MSG_INVALID_R_FLAG ));
  500.   }
  501.  
  502.   /*
  503.      * Merge new P(ath) setting into other options
  504.      *  "Pdir" = Receive files into directory "dir" if RN selected
  505.      *  "dir" can by any valid existing directory, with or without trailing "/"
  506.    */
  507.   if (p = find_option (buf, 'P'))
  508.   {
  509.     strcpy (sv->option_p, p);
  510.     p = sv->option_p + strcspn (sv->option_p, " ,\t\r\n");
  511.     *p = '\0';
  512.   }
  513.  
  514.   /* Maximum packet size. Must be <=8192 */
  515.  
  516.   if (p = find_option (buf, 'M'))
  517.   {
  518.     len = atol (p);
  519.     if (len < MINBLOCK) len = MINBLOCK;
  520.     if (len > MAXGOODNEEDED || len > KSIZE) len = KSIZE;
  521.     xprsprintf (sv->option_m, "%ld", len);
  522.   }
  523.  
  524.   /* Modify BPS Rate If We Have The BPS Rate Locked */
  525.   if (p = find_option(buf,'C'))
  526.   {
  527.     len = atol(p);
  528.     if ((len < 300)||(len > 58600)) len = 0;
  529.     xprsprintf(sv->option_c,"%ld",len);
  530.   }
  531.  
  532.   if (p = find_option(buf,'N'))
  533.   {
  534.     if (*p == 'Y' || *p == 'N') *sv->option_n = *p;
  535.       else ioerr(xio,GetLocalString( &li, MSG_INVALID_N_FLAG ));
  536.   }
  537.   if (p = find_option(buf,'Q'))
  538.   {
  539.     if (*p == 'Y' || *p == 'N') *sv->option_q = *p;
  540.       else ioerr(xio,GetLocalString( &li, MSG_INVALID_Q_FLAG ));
  541.   }
  542.   if (p = find_option(buf,'Z'))
  543.   {
  544.     if (*p == 'Y' || *p == 'N') *sv->option_z = *p;
  545.       else ioerr(xio, GetLocalString( &li, MSG_INVALID_Z_FLAG ));
  546.   }
  547.   if (p = find_option (buf, 'Y'))
  548.   {
  549.     if (*p == 'Y' || *p == 'N') *sv->option_y = *p;
  550.       else ioerr (xio, GetLocalString( &li, MSG_INVALID_Y_FLAG ));
  551.   }
  552.   if (p = find_option (buf, 'X'))
  553.   {
  554.     len = atol (p);
  555.     if (len < MINRXTO) len = MINRXTO;
  556.     if (len > MAXRXTO) len = MAXRXTO;
  557.     xprsprintf (sv->option_x, "%ld", len);
  558.   }
  559.  
  560.  
  561. #ifdef KDEBUG
  562. KPrintF("XProtocolSetup\nT%s,O%s,B%s,F%s,E%s,A%s\nD%s,K%s,S%s,R%s,P%s,M%s\nC%s,N%s,Q%s,Z%s\n",
  563.                   sv->option_t, sv->option_o, sv->option_b, sv->option_f,
  564.                   sv->option_e, sv->option_a, sv->option_d, sv->option_k,
  565.                   sv->option_s, sv->option_r, sv->option_p, sv->option_m,
  566.                   sv->option_c, sv->option_n, sv->option_q, sv->option_z,
  567.                   sv->option_y, sv->option_x);
  568.  
  569. #endif
  570.   if (*sv->option_y == 'N')
  571.   {
  572.     return (*sv->option_a == 'Y') ? 
  573.       XPRS_SUCCESS | XPRS_NORECREQ | XPRS_HOSTMON :
  574.       XPRS_SUCCESS | XPRS_NORECREQ;
  575.   }
  576.   else
  577.   {
  578.     return (*sv->option_a == 'Y') ? 
  579.       XPRS_SUCCESS | XPRS_NORECREQ | XPRS_HOSTMON | XPRS_XPR2001 | XPRS_DOUBLE :
  580.       XPRS_SUCCESS | XPRS_NORECREQ | XPRS_XPR2001 | XPRS_DOUBLE;
  581.   }
  582. }                                /* End of long XProtocolSetup() */
  583.  
  584. /**********************************************************
  585.  *      long XProtocolCleanup(struct XPR_IO *xio)
  586.  *
  587.  * Called by comm program to give us a chance to clean
  588.  * up before program ends
  589.  **********************************************************/
  590. long __saveds __asm
  591. XProtocolCleanup (register __a0 struct XPR_IO *xio)
  592. {
  593.   /* Release option memory, if any */
  594.   if (xio->xpr_data)
  595.   {
  596.     FreeMem (xio->xpr_data, (long) sizeof (struct SetupVars));
  597.     xio->xpr_data = NULL;
  598.   }
  599.  
  600.   return XPRS_SUCCESS;
  601. }                                /* End of long XProtocolCleanup() */
  602.  
  603. /**********************************************************
  604.  *      long XProtocolHostMon(struct XPR_IO *xio,
  605.  *         char *serbuff, long actual, long maxsize)
  606.  *
  607.  * Called by comm program upon our request (XPRS_HOSTMON)
  608.  * to let us monitor the incoming data stream for our
  609.  * receiver auto-activation string (ZRQINIT packet).
  610.  * We only ask for this to be called if option AY is set.
  611.  **********************************************************/
  612. long __saveds __asm
  613. XProtocolHostMon (
  614.                    register __a0 struct XPR_IO *xio,
  615.                    register __a1 char *serbuff,
  616.                    register __d0 long actual,
  617.                    register __d1 long maxsize)
  618. {
  619.   static UBYTE startrcv[] =
  620.   {
  621.     ZPAD, ZDLE, ZHEX, '0', '0'
  622.   };
  623.   struct SetupVars *sv;
  624.  
  625.   if (!(sv = (void *) xio->xpr_data))
  626.     return actual;                /* XProtocolSetup() never called?! */
  627.  
  628.   if (!sv->matchptr)
  629.     sv->matchptr = startrcv;
  630.  
  631.   /*
  632.      * Scan through serbuff to see if we can match all bytes in the start
  633.      * string in sequence.
  634.   */
  635.   for (sv->bufpos = serbuff; sv->bufpos < serbuff + actual; ++sv->bufpos)
  636.   {
  637.     if (*sv->bufpos == *sv->matchptr)
  638.     {                        /* if data matches current position in match */
  639.       ++sv->matchptr;        /* string, increment match position */
  640.       if (!*sv->matchptr)
  641.       {                        /* if at end of match string, it all matched */
  642.         sv->buflen = actual - (sv->bufpos - serbuff);
  643.         XProtocolReceive (xio);
  644.         sv->matchptr = startrcv;
  645.         actual = 0;
  646.         break;
  647.       }
  648.     }
  649.     else if (sv->matchptr > startrcv)
  650.     {                        /* mismatch?  Reset to start of match string */
  651.       sv->matchptr = startrcv;
  652.       if (*sv->bufpos == *sv->matchptr)
  653.         ++sv->matchptr;
  654.     }
  655.   }
  656.   sv->bufpos = NULL;
  657.   return actual;
  658. }
  659.  
  660. /**********************************************************
  661.  *      long XProtocolUserMon(struct XPR_IO *xio,
  662.  *         char *serbuff, long actual, long maxsize)
  663.  *
  664.  * Called by comm program to let us monitor user's inputs;
  665.  * we never ask for this to be called, but it's better to
  666.  * recover gracefully than guru the machine.
  667.  **********************************************************/
  668. long __saveds __asm
  669. XProtocolUserMon (
  670.                    register __a0 struct XPR_IO *xio,
  671.                    register __a1 char *serbuff,
  672.                    register __d0 long actual,
  673.                    register __d1 long maxsize)
  674. {
  675.   return actual;
  676. }
  677.  
  678. /**********************************************************
  679.  *      struct Vars *setup(struct XPR_IO *io)
  680.  *
  681.  * Perform setup and initializations common to both Send
  682.  * and Receive routines
  683.  **********************************************************/
  684. struct Vars *
  685. setup (struct XPR_IO *io)
  686. {
  687. /*
  688.   static long bauds[] =
  689.   {
  690.     110, 300, 1200, 2400,
  691.     4800, 9600, 19200, 31250,
  692.     38400, 57600, 76800, 115200
  693.   };
  694. */
  695.   static long bauds[] = 
  696.   { 
  697.     300,600,1200,2400,
  698.     4800,7200,9600,12000,
  699.     14400,16800,19200,31250,
  700.     38400,57600,76800,115200
  701.   };
  702.  
  703.   struct SetupVars *sv;
  704.   struct Vars *v;
  705.   long origbuf, newstatus;
  706.  
  707. #ifdef DEBUGLOG
  708.   long i, *lng;
  709. #endif
  710.  
  711.   /* Make sure comm program supports the required call-back functions */
  712.   if (!io->xpr_update)
  713.     return NULL;
  714.  
  715.   if (!io->xpr_fopen || !io->xpr_fclose || !io->xpr_fread
  716.       || !io->xpr_fwrite || !io->xpr_fseek || !io->xpr_sread
  717.       || !io->xpr_swrite)
  718.   {
  719.     ioerr (io, GetLocalString( &li, MSG_COMM_PROG_MISSING ));
  720.     return NULL;
  721.   }
  722.  
  723.   /* Hook in default transfer options if XProtocolSetup wasn't called */
  724.   if (!(sv = (void *) io->xpr_data))
  725.   {
  726. /*    io->xpr_data = AllocMem ((ULONG) sizeof (struct SetupVars), MEMF_CLEAR);  */
  727.     io->xpr_data = AllocMem ((long) sizeof (struct SetupVars), MEMF_CLEAR);
  728.     if (!(sv = (void *) io->xpr_data))
  729.     {
  730.       ioerr (io, GetLocalString( &li, MSG_NOT_ENOUGH_MEMORY ));
  731.       return NULL;
  732.     }
  733.     *sv = Default_Config;
  734.   }
  735.  
  736.   /* Allocate memory for our unshared variables, to provide reentrancy */
  737. /*  if (!(v = AllocMem ((ULONG) sizeof (struct Vars), MEMF_CLEAR))) */
  738.   if (!(v = AllocMem ((long) sizeof (struct Vars), MEMF_CLEAR)))
  739.   {
  740.   nomem:
  741.     ioerr (io, GetLocalString( &li, MSG_NOT_ENOUGH_MEMORY ));
  742.     return NULL;
  743.   }
  744.   v->Modemchar = v->Modembuf;
  745.  
  746.   /*
  747.      * Allocate memory for our file I/O buffer; if we can't get as much as
  748.      * requested, keep asking for less until we hit minimum before giving up
  749.    */
  750.   v->Filebufmax = origbuf = atol (sv->option_b) * 1024;
  751. /*  while (!(v->Filebuf = AllocMem ((ULONG) v->Filebufmax, MEMF_ANY)))  */
  752.   while (!(v->Filebuf = AllocMem (v->Filebufmax,0L)))
  753.   {
  754.     if (v->Filebufmax > 1024)  v->Filebufmax -= 1024;
  755.     else
  756.     {
  757.       FreeMem (v, (long) sizeof (struct Vars));
  758.       goto nomem;
  759.     }
  760.   }
  761.  
  762.  v->Ksize = atol(sv->option_m);
  763.  v->StartTimeout=atol(sv->option_x);
  764.  
  765.  if((v->Ksize * 2) > v->Filebufmax)
  766.   {
  767.     if(v->Filebufmax >=  1024) { v->Ksize = 512;  strcpy(sv->option_m,"512" ); }
  768.     if(v->Filebufmax >=  2048) { v->Ksize = 1024; strcpy(sv->option_m,"1024"); }
  769.     if(v->Filebufmax >=  4096) { v->Ksize = 2048; strcpy(sv->option_m,"2048"); }
  770.     if(v->Filebufmax >=  8192) { v->Ksize = 4096; strcpy(sv->option_m,"4096"); }
  771.     if(v->Filebufmax >= 16384) { v->Ksize = 8192; strcpy(sv->option_m,"8192"); }
  772. /*    v->Ksize = atol(sv->option_m);  */
  773.   }
  774.  
  775.   /* If framelength was intended to match buffer size, stay in sync */
  776.   v->Tframlen = atol (sv->option_f);
  777.   if (v->Tframlen && v->Tframlen == origbuf)
  778.     v->Tframlen = v->Filebufmax;
  779.  
  780.   v->ErrorLimit = atol (sv->option_e);
  781.  
  782.   /* Copy caller's io struct into our Vars for easier passing */
  783.   v->io = *io;
  784.  
  785. #ifdef DEBUGLOG
  786.   if (!DebugLog)
  787.     DebugLog = (char *) (*v->io.xpr_fopen) (DebugName, "w");
  788.   dlog (v, "XPR_IO struct:\n");
  789.   for (i = 0, lng = (long *) io; i < sizeof (struct XPR_IO) / 4; ++i)
  790.   {
  791.     xprsprintf (v->Msgbuf, "  %08lx\n", *lng++);
  792.     dlog (v, v->Msgbuf);
  793.   }
  794.   D (DEBUGINFO);
  795. #endif
  796.  
  797.   /* Get baud rate; set serial port mode if necessary (and possible) */
  798.   if (v->io.xpr_setserial)
  799.   {
  800.     v->Oldstatus = (*v->io.xpr_setserial) (-1L);
  801.     if (v->Oldstatus != -1)
  802.     {
  803.       /*
  804.          * ZModem requires 8 data bits, no parity (full transparency),
  805.          *  leave other settings alone
  806.        */
  807.       newstatus = v->Oldstatus & 0xFFFFE0BC;
  808.       /*
  809.          * newstatus |= on_flags; Here's where we'd turn bits on if we
  810.          * needed to
  811.        */
  812.       if (newstatus != v->Oldstatus)
  813.         (*v->io.xpr_setserial) (newstatus);
  814.       v->Baud = bauds[(newstatus >> 16) & 0xFF];
  815.  
  816. #ifdef DEBUGLOG
  817.       xprsprintf (v->Msgbuf,
  818.                   "Old serial status = %lx, new = %lx, baud = %ld\n",
  819.                   v->Oldstatus, newstatus, v->Baud);
  820.       dlog (v, v->Msgbuf);
  821.       D (DEBUGINFO);
  822. #endif
  823.     }
  824.     else
  825.       v->Baud = 2400;
  826.       /* If no xpr_setserial(), muddle along with most likely guess */
  827.   }
  828.   else
  829.     v->Baud = 2400;
  830.  
  831.   v->FTNmode = (*sv->option_z == 'Y') ? TRUE : FALSE;
  832.   v->dzap = (*sv->option_q == 'Y') ? TRUE : FALSE;
  833.   v->NoFiles = (*sv->option_n == 'Y') ? TRUE : FALSE;
  834.   v->SmallBlocks = (*sv->option_m == 1024) ? TRUE : FALSE;
  835.   v->NewBaud = atol(sv->option_c);
  836.   v->NoMask = (*sv->option_y == 'N') ? TRUE : FALSE; 
  837.   return v;
  838. }                                /* End of struct Vars *setup() */
  839.  
  840. /**********************************************************
  841.  *      void set_textmode(struct Vars *v)
  842.  *
  843.  * Set text/binary mode flags in accordance with T option
  844.  * setting
  845.  **********************************************************/
  846. void
  847. set_textmode (struct Vars *v)
  848. {
  849.   struct SetupVars *sv;
  850.   long i;
  851.  
  852. #ifdef DEBUGLOG
  853.   D (DEBUGINFO);
  854. #endif
  855.  
  856.   sv = (void *) v->io.xpr_data;
  857.   switch (*sv->option_t)
  858.     {
  859.     case 'Y':  /* Force text mode on receive; suggest text mode on send */
  860.     TY:
  861.       v->Rxascii = TRUE;
  862.       v->Rxbinary = FALSE;
  863.       v->Lzconv = ZCNL;
  864.       break;
  865.     case 'N': /* Force binary mode on receive; suggest binary mode on send */
  866.     TN:
  867.       v->Rxascii = FALSE;
  868.       v->Rxbinary = TRUE;
  869.       v->Lzconv = ZCBIN;
  870.       break;
  871.     case 'C':                        /* Ask comm program for proper mode for this file */
  872.       if (v->io.xpr_finfo)
  873.         {
  874.           i = (*v->io.xpr_finfo) (v->Filename, 2L);
  875.           if (i == 1)                /* Comm program says use binary mode */
  876.             goto TN;
  877.           if (i == 2)                /* Comm program says use text mode */
  878.             goto TY;
  879.         }
  880.       /* xpr_finfo() not provided (or failed); default to T? */
  881.     case '?':
  882.       v->Rxascii = v->Rxbinary = FALSE;
  883.       v->Lzconv = 0;
  884.       break;
  885.     }
  886. }                                /* End of void set_textmode() */
  887.  
  888. /**********************************************************
  889.  *      UBYTE *find_option(UBYTE *buf, UBYTE option)
  890.  *
  891.  * Search for specified option setting in string
  892.  **********************************************************/
  893. UBYTE *
  894. find_option (UBYTE * buf, UBYTE option)
  895. {
  896.   while (*buf)
  897.     {
  898.       buf += strspn (buf, " ,\t\r\n");
  899.       if (*buf == option)
  900.         return ++buf;
  901.       buf += strcspn (buf, " ,\t\r\n");
  902.     }
  903.  
  904.   return NULL;
  905. }                                /* End of UBYTE *find_option() */
  906.  
  907. /**********************************************************
  908.  *      void canit(struct Vars *v)
  909.  *
  910.  * send cancel string to get the other end to shut up
  911.  **********************************************************/
  912. void
  913. canit (struct Vars *v)
  914. {
  915.   static char canistr[] =
  916.   {
  917.     24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
  918.     8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0
  919.   };
  920.  
  921. #ifdef DEBUGLOG
  922.   D (DEBUGINFO);
  923. #endif
  924.  
  925.   zmputs (v, canistr);
  926. }                                /* End of void canit() */
  927.  
  928. /**********************************************************
  929.  *      void zmputs(struct Vars *v, UBYTE *s)
  930.  *
  931.  * Send a string to the modem, with processing for \336 (sleep 1 sec)
  932.  * and \335 (break signal, ignored since XPR spec doesn't support it)
  933.  **********************************************************/
  934. void
  935. zmputs (struct Vars *v, UBYTE * s)
  936. {
  937.   UBYTE c;
  938.  
  939. #ifdef DEBUGLOG
  940.   D (DEBUGINFO);
  941. #endif
  942.  
  943.   while (*s)
  944.     {
  945.       switch (c = *s++)
  946.         {
  947.         case '\336':
  948. #ifdef zedzap
  949.           XprTimeOut(50L);
  950. #else
  951.           Delay (50L);  
  952. #endif
  953.         case '\335':
  954.           break;
  955.         default:
  956.           sendline (v, c);
  957.         }
  958.     }
  959.   sendbuf (v);
  960. }                                /* End of void zmputs() */
  961.  
  962. /**********************************************************
  963.  *      void xsendline(struct Vars *v, UBYTE c)
  964.  *
  965.  * Write one character to the modem
  966.  **********************************************************/
  967. void
  968. xsendline (struct Vars *v, UBYTE c)
  969. {
  970.   v->Outbuf[v->Outbuflen++] = c;
  971.   if (v->Outbuflen >= sizeof (v->Outbuf))
  972.     sendbuf (v);
  973.  
  974. #ifdef DEBUGLOG
  975.   D (DEBUGINFO);
  976. #endif
  977.  
  978. }                                /* End of void xsendline() */
  979.  
  980. /**********************************************************
  981.  *      void sendbuf(struct Vars *v)
  982.  *
  983.  * Send any data waiting in modem output buffer
  984.  **********************************************************/
  985. void
  986. sendbuf (struct Vars *v)
  987. {
  988. #ifdef DEBUGLOG
  989.   D (DEBUGINFO);
  990. #endif
  991.  
  992.   if (v->Outbuflen)
  993.     {
  994.       (*v->io.xpr_swrite) (v->Outbuf, (long) v->Outbuflen);
  995.       v->Outbuflen = 0;
  996.     }
  997. }                                /* End of void sendbuf() */
  998.  
  999. /**********************************************************
  1000.  *      short readock(struct Vars *v, short tenths)
  1001.  *
  1002.  * Get a byte from the modem;
  1003.  * return TIMEOUT if no read within timeout tenths of a
  1004.  * second, return RCDO if carrier lost or other fatal error
  1005.  * (sread returns -1).  Added in some buffering so we
  1006.  * wouldn't hammer the system with single-byte serial port
  1007.  * reads.  Also, the buffering makes char_avail() a lot
  1008.  * easier to implement.
  1009.  **********************************************************/
  1010. short
  1011. readock (struct Vars *v, short tenths)
  1012. {
  1013.   long t;
  1014.  
  1015. #ifdef DEBUGLOG
  1016.   D (DEBUGINFO);
  1017. #endif
  1018.  
  1019.   /* If there's data waiting in our buffer, return next byte */
  1020.   if (v->Modemcount)
  1021.     {
  1022.     gotdata:
  1023.       --v->Modemcount;
  1024.       return (short) (*v->Modemchar++);
  1025.     }
  1026.   /*
  1027.      * Our buffer is empty; see if there's anything waiting in system buffer.
  1028.      * If the caller is in a hurry, don't wait around, but if it can spare
  1029.      * a half second, wait a bit and build up some input so we don't do as
  1030.      * many sread() calls.
  1031.    */
  1032.   t = (tenths < 5) ? 0 : 500000;
  1033.  
  1034. #ifdef DEBUGLOG
  1035.   xprsprintf (v->Msgbuf,
  1036.               "Input buffer empty; calling sread for %ld bytes, %ld usec\n",
  1037.               (long) sizeof (v->Modembuf), t);
  1038.   dlog (v, v->Msgbuf);
  1039.   D (DEBUGINFO);
  1040. #endif
  1041.   v->Modemcount = (*v->io.xpr_sread) (v->Modembuf, (long) sizeof (v->Modembuf), t);
  1042.  
  1043. #ifdef DEBUGLOG
  1044.   xprsprintf (v->Msgbuf, "   sread returned %ld\n", v->Modemcount);
  1045.   dlog (v, v->Msgbuf);
  1046.   D (DEBUGINFO);
  1047. #endif
  1048.   if (v->Modemcount < 0)        /* Carrier dropped or other fatal error; abort */
  1049.     {
  1050.       v->Modemcount = 0;
  1051.       return RCDO;
  1052.     }
  1053.   else if (!v->Modemcount)        /* Nothing in system buffer; try waiting */
  1054.     {
  1055.       t = tenths * 100000L - t;
  1056. #ifdef DEBUGLOG
  1057.       xprsprintf (v->Msgbuf, "   calling sread for 1 byte, %ld usec\n", t);
  1058.       dlog (v, v->Msgbuf);
  1059.       D (DEBUGINFO);
  1060. #endif
  1061.       v->Modemcount = (*v->io.xpr_sread) (v->Modembuf, 1L, t);
  1062. #ifdef DEBUGLOG
  1063.       xprsprintf (v->Msgbuf, "   sread returned %ld\n", v->Modemcount);
  1064.       dlog (v, v->Msgbuf);
  1065.       D (DEBUGINFO);
  1066. #endif
  1067.       if (v->Modemcount < 0)
  1068.         {
  1069.           v->Modemcount = 0;
  1070.           return RCDO;
  1071.         }
  1072.       else if (!v->Modemcount)        /* Nothing received in time */
  1073.         return TIMEOUT;
  1074.     }
  1075.   v->Modemchar = v->Modembuf;        /* Reset buffer pointer to start of data */
  1076.   goto gotdata;
  1077. }                                /* End of short readock() */
  1078.  
  1079. /**********************************************************
  1080.  *      char char_avail(struct Vars *v)
  1081.  *
  1082.  * Check if there's anything available to read from the
  1083.  * modem
  1084.  **********************************************************/
  1085. char
  1086. char_avail (struct Vars *v)
  1087. {
  1088. #ifdef DEBUGLOG
  1089.   D (DEBUGINFO);
  1090. #endif
  1091.  
  1092.   if (v->Modemcount)
  1093.     return TRUE;
  1094.  
  1095.   /* No data in our buffer; check system's input buffer */
  1096.   v->Modemcount = (*v->io.xpr_sread)
  1097.     (v->Modembuf, (long) sizeof (v->Modembuf), 0L);
  1098.   if (v->Modemcount < 1)        /* Nothing in system buffer either */
  1099.     {
  1100.       v->Modemcount = 0;
  1101.       return FALSE;
  1102.     }
  1103.   else
  1104.     /* System buffer had something waiting for us */
  1105.     {
  1106.       v->Modemchar = v->Modembuf;
  1107.       return TRUE;
  1108.     }
  1109. }                                /* End of char char_avail() */
  1110.  
  1111. /**********************************************************
  1112.  *      void update_rate(struct Vars *v)
  1113.  *
  1114.  * Update the elapsed time, expected total time, and
  1115.  * effective data transfer rate values for status display
  1116.  **********************************************************/
  1117. void
  1118. update_rate (struct Vars *v)
  1119. {
  1120.   ULONG sent, elapsed, expect;
  1121.   short hr, min;
  1122.   struct timeval tv;
  1123.  
  1124. #ifdef DEBUGLOG
  1125.   D (DEBUGINFO);
  1126. #endif
  1127.  
  1128.   /* Compute effective data rate so far in characters per second */
  1129.   sent = v->xpru.xpru_bytes - v->Strtpos;
  1130.   getsystime (&tv);
  1131.   elapsed = (tv.tv_secs & 0x7FFFFF) * 128 + tv.tv_micro / 8192;
  1132.   elapsed -= (v->Starttime.tv_secs & 0x7FFFFF) * 128 + v->Starttime.tv_micro / 8192;
  1133.   if (elapsed < 128 || elapsed > 0x7FFFFF)
  1134.     elapsed = 128;
  1135.   /*
  1136.      * If we haven't transferred anything yet (just starting), make reasonable
  1137.      * guess (95% throughput); otherwise, compute actual effective transfer
  1138.      * rate
  1139.    */
  1140.  
  1141.   if (v->NewBaud == 0)
  1142.     v->xpru.xpru_datarate = (sent) ? (sent * 128 / elapsed) : (v->Baud * 95 / 1000);
  1143.   else
  1144.     v->xpru.xpru_datarate = (sent) ? (sent * 128 / elapsed) : (v->NewBaud * 95 / 1000);
  1145.  
  1146.   /* Compute expected total transfer time based on data rate so far */
  1147.   if (v->xpru.xpru_filesize < 0)
  1148.     expect = 1;                /* Don't know filesize; display time=1; was 0 thas to nice for GURU 8000 0005 */
  1149.   else
  1150.   {
  1151.    if((v->xpru.xpru_datarate != 0) && ((v->xpru.xpru_filesize - v->Strtpos) != 0))
  1152.       expect = (v->xpru.xpru_filesize - v->Strtpos) / v->xpru.xpru_datarate;
  1153.     else
  1154.       expect = 1; /* Display 1 secs better than nothing... */
  1155.   }
  1156.  
  1157.   hr = expect / 3600;                /* How many whole hours */
  1158.   expect -= hr * 3600;                /* Remainder not counting hours */
  1159.   min = expect / 60;                /* How many whole minutes */
  1160.   expect -= min * 60;                /* Remaining seconds */
  1161.   xprsprintf (v->Msgbuf, "%02ld:%02ld:%02ld", (long) hr, (long) min, expect);
  1162.   v->xpru.xpru_expecttime = (char *) v->Msgbuf;
  1163.  
  1164.   /* Compute elapsed time for this transfer so far */
  1165.   elapsed /= 128;
  1166.   hr = elapsed / 3600;
  1167.   elapsed -= hr * 3600;
  1168.   min = elapsed / 60;
  1169.   elapsed -= min * 60;
  1170.   xprsprintf (v->Msgbuf + 20, "%02ld:%02ld:%02ld", (long) hr, (long) min,
  1171.               elapsed);
  1172.   v->xpru.xpru_elapsedtime = (char *) v->Msgbuf + 20;
  1173. }                                /* End of void update_rate() */
  1174.  
  1175. /**********************************************************
  1176.  *      long bfopen(struct Vars *v, UBYTE *mode)
  1177.  *
  1178.  * Buffered file I/O fopen() interface routine
  1179.  **********************************************************/
  1180. long
  1181. bfopen (struct Vars *v, UBYTE * mode)
  1182. {
  1183.   /* Initialize file-handling variables */
  1184.   v->Filebufpos = v->Filebuflen = v->Filebufcnt = 0;
  1185.   v->Fileflush = FALSE;
  1186.   v->Filebufptr = v->Filebuf;
  1187.   /* Open the file */
  1188. #ifdef DEBUGLOG
  1189.   xprsprintf (v->Msgbuf, "bfopen: %s %s\n", v->Filename, mode);
  1190.   dlog (v, v->Msgbuf);
  1191.   D (DEBUGINFO);
  1192. #endif
  1193.   return (*v->io.xpr_fopen) (v->Filename, mode);
  1194. }                                /* End of long bfopen() */
  1195.  
  1196. /**********************************************************
  1197.  *      void bfclose(struct Vars *v)
  1198.  *
  1199.  * Buffered file I/O fclose() interface routine
  1200.  **********************************************************/
  1201. void
  1202. bfclose (struct Vars *v)
  1203. {
  1204. #ifdef DEBUGLOG
  1205.   D (DEBUGINFO);
  1206. #endif
  1207.  
  1208.   if (v->File)
  1209.     {
  1210.       /* If bfwrite() left data in buffer, flush it out before closing */
  1211.       if (v->Fileflush)
  1212.         (*v->io.xpr_fwrite) (v->Filebuf, 1L, v->Filebufcnt, v->File);
  1213.       /* Close the file */
  1214.       (*v->io.xpr_fclose) (v->File);
  1215.       v->File = NULL;
  1216.     }
  1217. }                                /* End of void bfclose() */
  1218.  
  1219. /**********************************************************
  1220.  *      void bfseek(struct Vars *v, long pos)
  1221.  *
  1222.  * Buffered file I/O fseek() interface routine
  1223.  **********************************************************/
  1224. void
  1225. bfseek (struct Vars *v, long pos)
  1226. {
  1227.   long offset;
  1228.  
  1229. #ifdef DEBUGLOG
  1230.   D (DEBUGINFO);
  1231. #endif
  1232.  
  1233.   /* If new file position is within currently buffered section,
  1234.      reset pointers */
  1235.   if (pos >= v->Filebufpos && pos < v->Filebufpos + v->Filebuflen)
  1236.     {
  1237.       offset = pos - v->Filebufpos;
  1238.       v->Filebufptr = v->Filebuf + offset;
  1239.       v->Filebufcnt = v->Filebuflen - offset;
  1240.       /* Otherwise, fseek() file & discard buffer contents to force new read */
  1241.     }
  1242.   else
  1243.     {
  1244.       (*v->io.xpr_fseek) (v->File, pos, 0L);
  1245.       v->Filebuflen = v->Filebufcnt = 0;
  1246.       v->Filebufpos = pos;
  1247.     }
  1248. }                                /* End of void bfseek() */
  1249.  
  1250. /**********************************************************
  1251.  *      long bfread(struct Vars *v, UBYTE *buf, long length)
  1252.  *
  1253.  * Buffered file I/O fread() interface routine
  1254.  **********************************************************/
  1255. long
  1256. bfread (struct Vars *v, UBYTE * buf, long length)
  1257. {
  1258.   long count, total = 0;
  1259.  
  1260. #ifdef DEBUGLOG
  1261.   D (DEBUGINFO);
  1262. #endif
  1263.  
  1264.   /* Keep going until entire request completed */
  1265.   while (length > 0)
  1266.     {
  1267.       /* Copy as much of the request as possible from the buffer */
  1268.       count = (length <= v->Filebufcnt) ? length : v->Filebufcnt;
  1269.       CopyMem (v->Filebufptr, buf, count);
  1270. #ifdef DEBUGLOG
  1271.       xprsprintf (v->Msgbuf, "bfread got %ld bytes from buffer\n", count);
  1272.       dlog (v, v->Msgbuf);
  1273.       D (DEBUGINFO);
  1274. #endif
  1275.       buf += count;
  1276.       total += count;
  1277.       length -= count;
  1278.       v->Filebufptr += count;
  1279.       v->Filebufcnt -= count;
  1280.  
  1281.       /* If we've emptied the buffer, read next buffer's worth */
  1282.       if (!v->Filebufcnt)
  1283.         {
  1284.           v->Filebufpos += v->Filebuflen;
  1285.           v->Filebufptr = v->Filebuf;
  1286.           v->Filebufcnt = v->Filebuflen
  1287.             = (*v->io.xpr_fread) (v->Filebuf, 1L, v->Filebufmax, v->File);
  1288. #ifdef DEBUGLOG
  1289.           xprsprintf (v->Msgbuf, "bfread read %ld bytes\n", v->Filebufcnt);
  1290.           dlog (v, v->Msgbuf);
  1291.           D (DEBUGINFO);
  1292. #endif
  1293.           /* If we hit the EOF, return with however much we read so far */
  1294.           if (!v->Filebufcnt)
  1295.             break;
  1296.         }
  1297.     }
  1298.   return total;
  1299. }                                /* End of long bfread() */
  1300.  
  1301. /**********************************************************
  1302.  *      long bfwrite(struct Vars *v, UBYTE *buf, long length)
  1303.  *
  1304.  * Buffered file I/O fwrite() interface routine
  1305.  **********************************************************/
  1306. long
  1307. bfwrite (struct Vars *v, UBYTE * buf, long length)
  1308. {
  1309.   long count, total = 0;
  1310.  
  1311. #ifdef DEBUGLOG
  1312.   D (DEBUGINFO);
  1313. #endif
  1314.  
  1315.   /* Keep going until entire request completed */
  1316.   while (length > 0)
  1317.     {
  1318.       /* Copy as much as will fit into the buffer */
  1319.       count = v->Filebufmax - v->Filebufcnt;
  1320.       if (length < count)
  1321.         count = length;
  1322.       CopyMem (buf, v->Filebufptr, count);
  1323. #ifdef DEBUGLOG
  1324.       xprsprintf (v->Msgbuf, "bfwrite buffered %ld bytes\n", count);
  1325.       dlog (v, v->Msgbuf);
  1326.       D (DEBUGINFO);
  1327. #endif
  1328.       buf += count;
  1329.       total += count;
  1330.       length -= count;
  1331.       v->Filebufptr += count;
  1332.       v->Filebufcnt += count;
  1333.       v->Fileflush = TRUE;
  1334.  
  1335.       /* If we've filled the buffer, write it out */
  1336.       if (v->Filebufcnt == v->Filebufmax)
  1337.       {
  1338.         count = (*v->io.xpr_fwrite) (v->Filebuf, 1L, v->Filebufcnt, v->File);
  1339. #ifdef DEBUGLOG
  1340. xprsprintf (v->Msgbuf, "bfwrite wrote %ld bytes\n", count);
  1341. dlog (v, v->Msgbuf);
  1342. D (DEBUGINFO);
  1343. #endif
  1344.         if (count < v->Filebufcnt)
  1345.           return -1;
  1346.         v->Filebufptr = v->Filebuf;
  1347.         v->Filebufcnt = 0;
  1348.         v->Fileflush = FALSE;
  1349.       }
  1350.     }
  1351.   return total;
  1352. }                                /* End of long bfwrite() */
  1353.  
  1354. /**********************************************************
  1355.  *      void ioerr(struct XPR_IO *io, char *msg)
  1356.  *
  1357.  * Have the comm program display an error message for us,
  1358.  * using a temporary XPR_UPDATE structure; used to display
  1359.  * errors before Vars gets allocated
  1360.  **********************************************************/
  1361. void
  1362. ioerr (struct XPR_IO *io, char *msg)
  1363. {
  1364.   struct XPR_UPDATE xpru;
  1365.  
  1366.   if (io->xpr_update)
  1367.     {
  1368.       xpru.xpru_updatemask = XPRU_ERRORMSG;
  1369.       xpru.xpru_errormsg = msg;
  1370.       (*io->xpr_update) (&xpru);
  1371.     }
  1372. }                                /* End of void ioerr() */
  1373.  
  1374. /**********************************************************
  1375.  *     void updstatus(struct Vars *v,char *filename,long status)
  1376.  *
  1377.  * Set the pass/fail status of this file
  1378.  * Have the comm program display the file status for us, using the
  1379.  * normal XPR_IO structure allocated in Vars
  1380.  **********************************************************/
  1381. void
  1382. updstatus (struct Vars *v, char *filename, long status, long mask)
  1383. {
  1384.   if (v->NoMask) mask=0;
  1385.   v->xpru.xpru_updatemask = XPRU_FILENAME | XPRU_STATUS | mask;
  1386.   v->xpru.xpru_filename = filename;
  1387.   v->xpru.xpru_status = status;
  1388.   (*v->io.xpr_update) (&v->xpru);
  1389. }
  1390.  
  1391. /**********************************************************
  1392.  *      void upderr(struct Vars *v, char *msg)
  1393.  *
  1394.  * Have the comm program display an error message for us, using the
  1395.  * normal XPR_IO structure allocated in Vars
  1396.  **********************************************************/
  1397. void
  1398. upderr (struct Vars *v, char *msg, long mask)
  1399. {
  1400.   if (v->NoMask) mask=0;
  1401.   v->xpru.xpru_updatemask = XPRU_ERRORMSG | mask;
  1402.   v->xpru.xpru_errormsg = msg;
  1403.   if (msg == v->Msgbuf)                /* Ensure message length < 50 */
  1404.     msg[48] = '\0';
  1405.   (*v->io.xpr_update) (&v->xpru);
  1406. #ifdef DEBUGLOG
  1407.   dlog (v, msg);
  1408.   dlog (v, "\n");
  1409.   D (DEBUGINFO);
  1410. #endif
  1411. }                                /* End of void upderr() */
  1412.  
  1413. /**********************************************************
  1414.  *      void updmsg(struct Vars *v,char *msg)
  1415.  *
  1416.  * Have the comm program display a normal message for us
  1417.  **********************************************************/
  1418. void
  1419. updmsg (struct Vars *v, char *msg, long mask)
  1420. {
  1421. #ifdef DEBUGLOG
  1422.   D (DEBUGINFO);
  1423. #endif
  1424.  
  1425.   if (v->NoMask) mask=0;
  1426.   v->xpru.xpru_updatemask = XPRU_MSG | mask;
  1427.   v->xpru.xpru_msg = msg;
  1428.   if (msg == v->Msgbuf)                /* Ensure message length < 50 */
  1429.     msg[48] = '\0';
  1430.   (*v->io.xpr_update) (&v->xpru);
  1431. #ifdef DEBUGLOG
  1432.   dlog (v, msg);
  1433.   dlog (v, "\n");
  1434.   D (DEBUGINFO);
  1435. #endif
  1436. }                                /* End of void updmsg() */
  1437.  
  1438. /**********************************************************
  1439.  *      long getfree(void)
  1440.  *
  1441.   * Figure out how many bytes are free on the drive we're uploading to.
  1442.  * Stubbed out for now; not supported by XPR spec.
  1443.  **********************************************************/
  1444. long
  1445. getfree (void)
  1446. {
  1447.   return 0x7FFFFFFF;
  1448. }                                /* End of long getfree() */
  1449.  
  1450. /**********************************************************
  1451.  *      char exist(struct Vars *v)
  1452.  *
  1453.  * Check whether file already exists; used to detect
  1454.  * potential overwrites
  1455.  **********************************************************/
  1456. char
  1457. exist (struct Vars *v)
  1458. {
  1459.   long file;
  1460.  
  1461. #ifdef DEBUGLOG
  1462.   D (DEBUGINFO);
  1463. #endif
  1464.  
  1465.   file = (*v->io.xpr_fopen) (v->Filename, "r");
  1466.   if (file)
  1467.   {
  1468.       (*v->io.xpr_fclose) (file);
  1469.       return TRUE;
  1470.   }
  1471.   else
  1472.   {
  1473.     return FALSE;
  1474.   }
  1475. }                                /* End of char exist() */
  1476.  
  1477. #ifdef DEBUGLOG
  1478. /**********************************************************
  1479.  *      void dlog(struct Vars *v, UBYTE *s)
  1480.  *
  1481.  * Write a message to the debug log
  1482.  **********************************************************/
  1483. void
  1484. dlog (struct Vars *v, UBYTE * s)
  1485. {
  1486.   /* Open the debug log if it isn't already open */
  1487.   if (!DebugLog)
  1488.     DebugLog = (char *) (*v->io.xpr_fopen) (DebugName, "a");
  1489.   (*v->io.xpr_fwrite) (s, 1L, (long) strlen (s), (long) DebugLog);
  1490.   /*
  1491.      * Close file to flush output buffer; comment these two lines out if
  1492.      * you aren't crashing your system and don't mind waiting until the
  1493.      * transfer finishes to look at your log file.
  1494.    */
  1495.   /* (*v->io.xpr_fclose)((long)DebugLog);
  1496.      * DebugLog = NULL;
  1497.    */
  1498.  
  1499. }                                /* End of void dlog() */
  1500. #endif
  1501. /* End of Utils.c source */
  1502.